package com.mxpio.erp.plan.mrp.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.mxpioframework.common.exception.MBootException;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mxpio.erp.common.enums.CommonEnums;
import com.mxpio.erp.common.enums.ItemEnums;
import com.mxpio.erp.common.plan.entity.ManufacturePlan;
import com.mxpio.erp.common.plan.entity.NetRequirementPlan;
import com.mxpio.erp.common.plan.entity.PurchasePlan;
import com.mxpio.erp.common.technology.entity.VBomInfo;
import com.mxpio.erp.common.technology.vo.ItemWithSubExtendsVO;
import com.mxpio.erp.common.workshop.entity.ManufactureOrderItem;
import com.mxpio.erp.plan.mrp.Context;
import com.mxpio.erp.plan.mrp.CountModelMap;
import com.mxpio.erp.plan.mrp.bo.CountModel;
import com.mxpio.erp.plan.mrp.service.LrpCoreProvider;
import com.mxpio.erp.plan.mrp.service.LrpCoreService;
import com.mxpio.erp.plan.util.PlanDateUtil;
import com.mxpioframework.common.util.BeanReflectionUtils;
import com.mxpioframework.jpa.JpaUtil;

@Service
public class LrpCoreServiceImpl implements LrpCoreService {
	
	private static final Logger log = LoggerFactory.getLogger(LrpCoreServiceImpl.class);

	@Autowired
	private LrpCoreProvider lrpCoreProvider;
	
	public Context context;
	
	@Override
	@Transactional(readOnly = false)
	public void clearAdvice() {
		log.info("MRP:===========clearAdvice start============");
		JpaUtil.lind(NetRequirementPlan.class).delete();
		JpaUtil.lind(ManufacturePlan.class).delete();
		JpaUtil.lind(PurchasePlan.class).delete();
		log.info("MRP:===========clearAdvice end============");
	}
	
	@Override
	@Transactional(readOnly = true)
	public void initContext(Context context) {
		log.info("MRP:===========Init start============");
		this.context = context;
		//初始化物料数据
		log.info("MRP:初始化物料数据");
		lrpCoreProvider.getItem(this.context);
		log.info("MRP:初始化物料数据-完成");
		//初始化Bom数据
		log.info("MRP:初始化Bom数据");
		lrpCoreProvider.getBom(this.context);
		log.info("MRP:初始化Bom数据-完成");
		//初始化订单数据
		if(context.isIncludeMO()){
			log.info("MRP:初始化订单数据");
			lrpCoreProvider.getOrderCount(this.context);
			log.info("MRP:初始化订单数据-完成");
		}else{
			context.setOrderCount(new CountModelMap<List<CountModel>>());
		}
		//初始化采购数据
		if(context.isIncludePO()){
			log.info("MRP:初始化采购数据");
			lrpCoreProvider.getPurchaseOrderCount(this.context);
			log.info("MRP:初始化采购数据-完成");
		}else{
			context.setPurchaseOrderCount(new CountModelMap<List<CountModel>>());
		}
		//初始化需求数据
		if(context.isIncludeSO()){
			log.info("MRP:初始化需求数据");
			lrpCoreProvider.getSalesOrderCount(this.context);
			log.info("MRP:初始化需求数据-完成");
		}else{
			context.setSalesOrderCount(new CountModelMap<List<CountModel>>());
		}
		
		//初始化库存数据
		if(context.isIncludeSG()){
			log.info("MRP:初始化库存数据");
			lrpCoreProvider.getStorage(this.context);
			log.info("MRP:初始化库存数据-完成");
		}else{
			context.setStorage(new CountModelMap<CountModel>());
		}
		
		log.info("MRP销售:"+context.getSalesOrderCount().size());
		log.info("MRP订单:"+context.getOrderCount().size());
		log.info("MRP订单行:"+context.getOrderLines().size());
		log.info("MRP采购:"+context.getPurchaseOrderCount().size());
		log.info("MRP库存:"+context.getStorage().size());
		log.info("MRP:===========Init end============");
	}

	//3. 需求自制合并
	private void consolidateMoDemand(List<NetRequirementPlan> demands, List<ManufacturePlan> manufacturePlans,
			ItemWithSubExtendsVO item) {
		/*BigDecimal fixedLotSize = item.getItemPlanProp().getFixedLotSize();
		BigDecimal incrementLotSize = item.getItemPlanProp().getIncrementLotSize();
		BigDecimal minPlanQuantity = item.getItemPlanProp().getMinPlanQuantity();*/
		
		ManufacturePlan currentOrder = null; 
		if(CollectionUtils.isNotEmpty(demands)){
			for(NetRequirementPlan netPlan : demands){
				
				if(CommonEnums.YesNo.NO.getCode().equals(item.getVirtualPart())){
					currentOrder = new ManufacturePlan();
					currentOrder.setQuantity(netPlan.getNumber());
					currentOrder.setItemCode(item.getItemCode());
					currentOrder.setMemo(netPlan.getRemark()+",");
					currentOrder.setDeliverDate(netPlan.getCompletePlanDate());
					currentOrder.setStartDate(netPlan.getShipmentDate());
					currentOrder.setMainWorkshop(item.getMainWorkshop());
					currentOrder.setWorkCenterCode(item.getWorkCenterCode());//工作中心
					//计划列表展示冗余字段
					currentOrder.setItemName(item.getItemName());
					currentOrder.setItemSpec(item.getItemSpec());
					currentOrder.setUnitCode(item.getUnitCode());
					currentOrder.setDrawingNo(item.getDrawingNo());
					
					for(int i=0; i<context.getItemIndexFields().size(); i++) {
						BeanReflectionUtils.setPropertyValue(currentOrder, context.getItemIndexFields().get(i), BeanReflectionUtils.getPropertyValue(netPlan, context.getItemIndexFields().get(i)));
					}

					if(CommonEnums.YesNo.YES.getCode().equals(item.getOutsourceAble())
							&& !CommonEnums.YesNo.YES.getCode().equals(item.getManufactureAble())){
						currentOrder.setOutsourceFlag(CommonEnums.YesNo.YES.getCode());//
					}else{
						currentOrder.setOutsourceFlag(CommonEnums.YesNo.NO.getCode());//
					}

					manufacturePlans.add(currentOrder);
				}
				
				
				/*// 固定批量存在,需求大于固定批量,则按照固定批量分隔订单
				if (currentOrder != null && fixedLotSize != null && BigDecimal.ZERO.compareTo(fixedLotSize) != 0 && BigDecimal.ZERO.compareTo(currentOrder.getQuantity())<0) {
					int planCount = currentOrder.getQuantity().divide(fixedLotSize, 0, BigDecimal.ROUND_UP).intValue();
					for(int i=0; i<planCount; i++){
						ManufacturePlan subOrder = new ManufacturePlan();
						BeanReflectionUtils.copyProperties(subOrder, currentOrder);
						subOrder.setQuantity(fixedLotSize);
						manufacturePlans.add(subOrder);
					}
					currentOrder.setQuantity(currentOrder.getQuantity().subtract(fixedLotSize.multiply(new BigDecimal(planCount))));
				}
				
				// 固定批量不存在，按照批量和增量计算
				if(currentOrder !=null && (fixedLotSize==null || BigDecimal.ZERO.compareTo(fixedLotSize)==0)
						&& (minPlanQuantity!=null && BigDecimal.ZERO.compareTo(minPlanQuantity)!=0)
						&& (incrementLotSize!=null && BigDecimal.ZERO.compareTo(incrementLotSize)!=0)
						&& BigDecimal.ZERO.compareTo(currentOrder.getQuantity())<0){
					ManufacturePlan subOrder = new ManufacturePlan();
					BeanReflectionUtils.copyProperties(subOrder, currentOrder);
					BigDecimal quantity = BigDecimal.ZERO;
					if(minPlanQuantity.compareTo(currentOrder.getQuantity())<0){
						quantity = minPlanQuantity.add(currentOrder.getQuantity().subtract(minPlanQuantity).divide(incrementLotSize, 0, BigDecimal.ROUND_UP).multiply(incrementLotSize));
					}else{
						quantity = minPlanQuantity;
					}
					subOrder.setQuantity(quantity);
					manufacturePlans.add(subOrder);
					currentOrder.setQuantity(quantity.subtract(currentOrder.getQuantity()));
				}
				
				//如果当前订单不存在
				if(currentOrder == null || BigDecimal.ZERO.compareTo(currentOrder.getQuantity())>=0){
					if(currentOrder == null){
						currentOrder = new ManufacturePlan();
						currentOrder.setQuantity(netPlan.getNumber());
					}else{
						currentOrder.setQuantity(currentOrder.getQuantity().add(netPlan.getNumber()));
					}
					
					currentOrder.setItemCode(item.getItemCode());
					currentOrder.setMemo(netPlan.getRemark()+",");
					currentOrder.setDeliverDate(netPlan.getCompletePlanDate());
					
					for(int i=0; i<context.getItemIndexFields().size(); i++) {
						BeanReflectionUtils.setPropertyValue(currentOrder, context.getItemIndexFields().get(i), BeanReflectionUtils.getPropertyValue(netPlan, context.getItemIndexFields().get(i)));
					}
				}else{
					currentOrder.setQuantity(currentOrder.getQuantity().add(netPlan.getNumber()));
					currentOrder.setMemo(currentOrder.getMemo()+netPlan.getRemark()+",");
					netPlan.setPlanNo(currentOrder.getPlanNo());
				}*/
			}
			
			/*if(currentOrder != null && BigDecimal.ZERO.compareTo(currentOrder.getQuantity()) < 0){
				if(fixedLotSize != null && BigDecimal.ZERO.compareTo(fixedLotSize) != 0){
					currentOrder.setQuantity(fixedLotSize);
				}else if((minPlanQuantity!=null && BigDecimal.ZERO.compareTo(minPlanQuantity)!=0)
						&& (incrementLotSize!=null && BigDecimal.ZERO.compareTo(incrementLotSize)!=0)){
					BigDecimal quantity = BigDecimal.ZERO;
					if(minPlanQuantity.compareTo(currentOrder.getQuantity())<0){
						quantity = minPlanQuantity.add(currentOrder.getQuantity().subtract(minPlanQuantity).divide(incrementLotSize, 0, BigDecimal.ROUND_UP).multiply(incrementLotSize));
					}else{
						quantity = minPlanQuantity;
					}
					currentOrder.setQuantity(quantity);
				}
				manufacturePlans.add(currentOrder);
				currentOrder = null;
			}*/
		}
	}
	//3. 需求采购合并
	private void consolidatePoDemand(List<NetRequirementPlan> demands, List<PurchasePlan> purchasePlans,
			ItemWithSubExtendsVO item) {
		/*BigDecimal fixedLotSize = item.getItemPlanProp().getFixedLotSize();
		BigDecimal incrementLotSize = item.getItemPlanProp().getIncrementLotSize();
		BigDecimal minPlanQuantity = item.getItemPlanProp().getMinPlanQuantity();*/
		
		PurchasePlan currentOrder = null; 
		if(CollectionUtils.isNotEmpty(demands)){
			for(NetRequirementPlan netPlan : demands){
				
				currentOrder = new PurchasePlan();
				currentOrder.setQuantity(netPlan.getNumber());
				currentOrder.setItemCode(item.getItemCode());
				currentOrder.setMemo(netPlan.getRemark()+",");
				currentOrder.setDeliverDate(netPlan.getCompletePlanDate());
				currentOrder.setStartDate(netPlan.getShipmentDate());
				//计划列表展示冗余字段
				currentOrder.setItemName(item.getItemName());
				currentOrder.setItemSpec(item.getItemSpec());
				currentOrder.setUnitCode(item.getUnitCode());
				currentOrder.setDrawingNo(item.getDrawingNo());
				for(int i=0; i<context.getItemIndexFields().size(); i++) {
					BeanReflectionUtils.setPropertyValue(currentOrder, context.getItemIndexFields().get(i), BeanReflectionUtils.getPropertyValue(netPlan, context.getItemIndexFields().get(i)));
				}
				
				purchasePlans.add(currentOrder);
				
				/*// 固定批量存在,需求大于固定批量,则按照固定批量分隔订单
				if (currentOrder != null && fixedLotSize != null && BigDecimal.ZERO.compareTo(fixedLotSize) != 0 && BigDecimal.ZERO.compareTo(currentOrder.getQuantity())<0) {
					int planCount = currentOrder.getQuantity().divide(fixedLotSize, 0, BigDecimal.ROUND_UP).intValue();
					for(int i=0; i<planCount; i++){
						PurchasePlan subOrder = new PurchasePlan();
						BeanReflectionUtils.copyProperties(subOrder, currentOrder);
						subOrder.setQuantity(fixedLotSize);
						purchasePlans.add(subOrder);
					}
					currentOrder.setQuantity(currentOrder.getQuantity().subtract(fixedLotSize.multiply(new BigDecimal(planCount))));
				}
				
				// 固定批量不存在，按照批量和增量计算
				if(currentOrder !=null && (fixedLotSize==null || BigDecimal.ZERO.compareTo(fixedLotSize)==0)
						&& (minPlanQuantity!=null && BigDecimal.ZERO.compareTo(minPlanQuantity)!=0)
						&& (incrementLotSize!=null && BigDecimal.ZERO.compareTo(incrementLotSize)!=0)
						&& BigDecimal.ZERO.compareTo(currentOrder.getQuantity())<0){
					PurchasePlan subOrder = new PurchasePlan();
					BeanReflectionUtils.copyProperties(subOrder, currentOrder);
					BigDecimal quantity = BigDecimal.ZERO;
					if(minPlanQuantity.compareTo(currentOrder.getQuantity())<0){
						quantity = minPlanQuantity.add(currentOrder.getQuantity().subtract(minPlanQuantity).divide(incrementLotSize, 0, BigDecimal.ROUND_UP).multiply(incrementLotSize));
					}else{
						quantity = minPlanQuantity;
					}
					subOrder.setQuantity(quantity);
					purchasePlans.add(subOrder);
					currentOrder.setQuantity(quantity.subtract(currentOrder.getQuantity()));
				}
				
				//如果当前订单不存在
				if(currentOrder == null || BigDecimal.ZERO.compareTo(currentOrder.getQuantity())>=0){
					if(currentOrder == null){
						currentOrder = new PurchasePlan();
						currentOrder.setQuantity(netPlan.getNumber());
					}else{
						currentOrder.setQuantity(currentOrder.getQuantity().add(netPlan.getNumber()));
					}
					
					currentOrder.setItemCode(item.getItemCode());
					currentOrder.setMemo(netPlan.getRemark()+",");
					currentOrder.setDeliverDate(netPlan.getCompletePlanDate());
					
					for(int i=0; i<context.getItemIndexFields().size(); i++) {
						BeanReflectionUtils.setPropertyValue(currentOrder, context.getItemIndexFields().get(i), BeanReflectionUtils.getPropertyValue(netPlan, context.getItemIndexFields().get(i)));
					}
				}else{
					currentOrder.setQuantity(currentOrder.getQuantity().add(netPlan.getNumber()));
					currentOrder.setMemo(currentOrder.getMemo()+netPlan.getRemark()+",");
					netPlan.setPlanNo(currentOrder.getPlanNo());
				}*/
			}
			
			/*if(currentOrder != null && BigDecimal.ZERO.compareTo(currentOrder.getQuantity()) < 0){
				if(fixedLotSize != null && BigDecimal.ZERO.compareTo(fixedLotSize) != 0){
					currentOrder.setQuantity(fixedLotSize);
				}else if((minPlanQuantity!=null && BigDecimal.ZERO.compareTo(minPlanQuantity)!=0)
						&& (incrementLotSize!=null && BigDecimal.ZERO.compareTo(incrementLotSize)!=0)){
					BigDecimal quantity = BigDecimal.ZERO;
					if(minPlanQuantity.compareTo(currentOrder.getQuantity())<0){
						quantity = minPlanQuantity.add(currentOrder.getQuantity().subtract(minPlanQuantity).divide(incrementLotSize, 0, BigDecimal.ROUND_UP).multiply(incrementLotSize));
					}else{
						quantity = minPlanQuantity;
					}
					currentOrder.setQuantity(quantity);
				}
				purchasePlans.add(currentOrder);
				currentOrder = null;
			}*/
		}
	}

	//1
	@Override
	@Transactional(readOnly = false)
	public void runLrp() {
		log.info("MRP:===========MRP start============");
		long start = System.currentTimeMillis();
		//遍历所有采购物料
		Map<String, ItemWithSubExtendsVO> purchaseItems = context.getPurchaseItems();
		Iterator<Map.Entry<String, ItemWithSubExtendsVO>> entries = purchaseItems.entrySet().iterator();
		while(entries.hasNext()){
			Map.Entry<String, ItemWithSubExtendsVO> entry = entries.next(); 
			//递归需求
			calculateDemands(entry.getValue());
		}
		
		CountModelMap<List<CountModel>> resultCounts = context.getAllmodels();
		
		List<NetRequirementPlan> demands = new ArrayList<>();
		List<PurchasePlan> purchasePlans = new ArrayList<>();
		List<ManufacturePlan> manufacturePlans = new ArrayList<>();
		
		Iterator<Entry<String, Map<String, List<CountModel>>>> it = resultCounts.entrySet().iterator();
		while(it.hasNext()){
			Entry<String, Map<String, List<CountModel>>> superEntry = it.next();
			for(Map.Entry<String, List<CountModel>> entry : superEntry.getValue().entrySet()) {
				ItemWithSubExtendsVO item = context.getItems().get(superEntry.getKey());
				List<NetRequirementPlan> currentMoDemands = new ArrayList<>();
				List<NetRequirementPlan> currentPoDemands = new ArrayList<>();
				if(item == null){
					continue;
				}
				if (item.getItemSource() == null
						|| ItemEnums.FeedingMode.STOCK.getTypeCode().equals(item.getItemPlanProp().getFeedingMode())
						|| ItemEnums.FeedingMode.JIT.getTypeCode().equals(item.getItemPlanProp().getFeedingMode())
						|| CommonEnums.YesNo.YES.getCode().equals(item.getVirtualPart())) {
					continue;
				}
				for(CountModel model : entry.getValue()){
					if(!item.getItemSource().equals(ItemEnums.ItemSource.P.getTypeCode())){
						NetRequirementPlan demand = new NetRequirementPlan();
						// 提前期=固定提前期+（数量/提前期批量）*变量提前期
						Integer leadTime = item.getItemLeadTimeProp().getFixedLeadTime().add(item.getItemLeadTimeProp().getVarLeadTime().multiply(model.getCount().divide(item.getItemLeadTimeProp().getLeadLotSize(),0,BigDecimal.ROUND_UP))).intValue();
						//计划完成时间
						demand.setCompletePlanDate(model.getOrderDate());
						demand.setShipmentDate(PlanDateUtil.rollDay(model.getOrderDate(), 0-leadTime));
						demand.setItemCode(item.getItemCode());
						demand.setNumber(model.getCount());
						demand.setRemark(model.getRemark());
						demands.add(demand);
						currentMoDemands.add(demand);
					}else{
						NetRequirementPlan demand = new NetRequirementPlan();
						// 提前期=固定提前期+（数量/提前期批量）*变量提前期
						Integer leadTime = item.getItemLeadTimeProp().getFixedLeadTime().add(item.getItemLeadTimeProp().getVarLeadTime().multiply(model.getCount().divide(item.getItemLeadTimeProp().getLeadLotSize(),0,BigDecimal.ROUND_UP))).intValue();
						//计划完成时间
						demand.setCompletePlanDate(model.getOrderDate());
						demand.setShipmentDate(PlanDateUtil.rollDay(model.getOrderDate(), 0-leadTime));
						demand.setItemCode(item.getItemCode());
						demand.setNumber(model.getCount());
						demand.setRemark(model.getRemark());
						demands.add(demand);
						currentPoDemands.add(demand);
					}
				}
				consolidateMoDemand(currentMoDemands, manufacturePlans, item);
				consolidatePoDemand(currentPoDemands, purchasePlans, item);
			}
		}
		JpaUtil.save(demands);
		JpaUtil.save(manufacturePlans);
		JpaUtil.save(purchasePlans);
		
		log.info("用时：" + (System.currentTimeMillis() - start));
		log.info("MRP:===========MRP end============");
	}
	
	//2
	@Transactional(readOnly = false)
	private void calculateDemands(ItemWithSubExtendsVO itemWithSubExtendsVO){
		Integer scale = itemWithSubExtendsVO.getScale()==null?0:itemWithSubExtendsVO.getScale();
		List<VBomInfo> boms = context.getBoms().get(itemWithSubExtendsVO.getItemCode());
		if(boms == null){
			boms = Collections.emptyList();
		}
		Map<String,List<CountModel>> resultCountModelsMap = context.getResultCount().get(itemWithSubExtendsVO.getItemCode());
		//
		if(resultCountModelsMap == null){
			for(VBomInfo bom : boms){
				ItemWithSubExtendsVO faItem = context.getItems().get(bom.getParentCode());
				ItemWithSubExtendsVO item = context.getItems().get(bom.getItemCode());
				if(faItem == null||faItem.getItemLeadTimeProp()==null) {
					continue;
				}
				if(item == null||item.getItemLeadTimeProp()==null){
					continue;
				}
				Integer itemScale = item.getScale()==null?0:item.getScale();;
				
				calculateDemands(faItem);
				//添加上层物料需求
				Map<String,List<CountModel>> faResultCountModelsMap = context.getAllmodels().get(bom.getParentCode());
				if(faResultCountModelsMap != null){
					for(Map.Entry<String,List<CountModel>> faResultCountModelsEntry : faResultCountModelsMap.entrySet()) {
						for(CountModel faModel : faResultCountModelsEntry.getValue()){
							CountModel resultModel = new CountModel();
							BigDecimal count = faModel.getCount().multiply(bom.getItemConsumption());
							count = count.setScale(itemScale, BigDecimal.ROUND_UP);
							resultModel.setCount(count);
							resultModel.setType(1);
							resultModel.setItemCode(itemWithSubExtendsVO.getItemCode());
							// 提前期=固定提前期+（数量/提前期批量）*变量提前期
							Integer leadTime = faItem.getItemLeadTimeProp().getFixedLeadTime().add(faItem.getItemLeadTimeProp().getVarLeadTime().multiply(count.divide(faItem.getItemLeadTimeProp().getLeadLotSize(),0,BigDecimal.ROUND_UP))).intValue();
							resultModel.setOrderDate(PlanDateUtil.rollDay(faModel.getOrderDate(), 0-leadTime));
							resultModel.setRemark(faModel.getRemark());
							
							if(resultCountModelsMap == null){
								resultCountModelsMap  = new HashMap<String,List<CountModel>>();
							}
							if(resultCountModelsMap.get(faResultCountModelsEntry.getKey()) == null) {
								resultCountModelsMap.put(faResultCountModelsEntry.getKey(), new ArrayList<CountModel>());
							}
							resultModel.setIndexes(faResultCountModelsEntry.getKey());
							resultCountModelsMap.get(faResultCountModelsEntry.getKey()).add(resultModel);
						}
					}
				}
				//添加上层物料订单需求
				Map<String,List<CountModel>> faOrderCountsMap = context.getOrderCount().get(bom.getParentCode());
				if(faOrderCountsMap != null){
					for(Map.Entry<String,List<CountModel>> faOrderCountsEntry : faOrderCountsMap.entrySet()) {
						
						for(CountModel faOrderCount : faOrderCountsEntry.getValue()){
							
							List<ManufactureOrderItem> moLines = context.getOrderLines().get(faOrderCount.getBoCode());
							if (moLines==null||moLines.size()==0){
								throw new MBootException("存在订单bom明细为空的订单："+faOrderCount.getBoCode());
							}
							BigDecimal count = BigDecimal.ZERO;
							for(ManufactureOrderItem moLine : moLines){
								if(bom.getItemCode().equals(moLine.getItemCode())){
									count = moLine.getQuantity().subtract(moLine.getActualQuantity()).add(moLine.getActualRejectQuantity());
									count = count.setScale(itemScale, BigDecimal.ROUND_UP);
									
									CountModel resultModel = new CountModel();
									resultModel.setCount(count);
									resultModel.setItemCode(itemWithSubExtendsVO.getItemCode());
									// 提前期=固定提前期+（数量/提前期批量）*变量提前期
									Integer leadTime = faItem.getItemLeadTimeProp().getFixedLeadTime().add(faItem.getItemLeadTimeProp().getVarLeadTime().multiply(count.divide(faItem.getItemLeadTimeProp().getLeadLotSize(),0,BigDecimal.ROUND_UP))).intValue();
									resultModel.setOrderDate(PlanDateUtil.rollDay(faOrderCount.getOrderDate(), 0-leadTime));
									resultModel.setType(1);
									resultModel.setRemark(faOrderCount.getRemark());
									resultModel.setIndexes(faOrderCountsEntry.getKey());
									if(resultCountModelsMap == null){
										resultCountModelsMap  = new HashMap<String,List<CountModel>>();
									}
									if(resultCountModelsMap.get(faOrderCountsEntry.getKey()) == null) {
										resultCountModelsMap.put(faOrderCountsEntry.getKey(), new ArrayList<CountModel>());
									}
									resultCountModelsMap.get(faOrderCountsEntry.getKey()).add(resultModel);
								}
							}
						}
					}
				}
			}
			if(resultCountModelsMap == null){
				resultCountModelsMap  = new HashMap<String,List<CountModel>>();
			}
			
			Map<String,List<CountModel>> allmodels = new HashMap<String,List<CountModel>>();
			
			Map<String,List<CountModel>> purchaseCounts = context.getPurchaseOrderCount().get(itemWithSubExtendsVO.getItemCode());
			if(purchaseCounts == null) {
				purchaseCounts = new HashMap<String,List<CountModel>>();
			}
			List<CountModel> purchaseCountsList = new ArrayList<>();
			for(Map.Entry<String,List<CountModel>> purchaseCountsEntry : purchaseCounts.entrySet()) {
				purchaseCountsList.addAll(purchaseCountsEntry.getValue());
			}
			Map<String,List<CountModel>> orderCounts = context.getOrderCount().get(itemWithSubExtendsVO.getItemCode());
			if(orderCounts == null) {
				orderCounts = new HashMap<String,List<CountModel>>();
			}
			List<CountModel> orderCountsList = new ArrayList<>();
			for(Map.Entry<String,List<CountModel>> orderCountsEntry : orderCounts.entrySet()) {
				orderCountsList.addAll(orderCountsEntry.getValue());
			}
			
			Map<String,List<CountModel>> salesCounts = context.getSalesOrderCount().get(itemWithSubExtendsVO.getItemCode());
			if(salesCounts == null) {
				salesCounts = new HashMap<String,List<CountModel>>();
			}
			List<CountModel> salesCountsList = new ArrayList<>();
			for(Map.Entry<String,List<CountModel>> salesCountsEntry : salesCounts.entrySet()) {
				salesCountsList.addAll(salesCountsEntry.getValue());
			}
			
			List<CountModel> resultCountModelsList = new ArrayList<CountModel>();
			
			for(Map.Entry<String,List<CountModel>> entry : resultCountModelsMap.entrySet()) {
				resultCountModelsList.addAll(entry.getValue());
			}
			
			if(CollectionUtils.isNotEmpty(orderCountsList)){
				resultCountModelsList.addAll(orderCountsList);
			}
			if(CollectionUtils.isNotEmpty(salesCountsList)){
				resultCountModelsList.addAll(salesCountsList);
			}
			if(CollectionUtils.isNotEmpty(purchaseCountsList)){
				resultCountModelsList.addAll(purchaseCountsList);
			}
			
			Collections.sort(resultCountModelsList);
			resultCountModelsMap.clear();
			for(CountModel model : resultCountModelsList) {
				if(resultCountModelsMap.get(model.getIndexes()) == null) {
					resultCountModelsMap.put(model.getIndexes(), new ArrayList<CountModel>());
				}
				resultCountModelsMap.get(model.getIndexes()).add(model);
			}
			
			Map<String,CountModel> storage = context.getStorage().get(itemWithSubExtendsVO.getItemCode());
			if(storage == null) {
				storage = new HashMap<String,CountModel>();
			}
			for(Map.Entry<String,CountModel> storageEntry : storage.entrySet()) {
				
				if(resultCountModelsMap.get(storageEntry.getKey()) == null) {
					resultCountModelsMap.put(storageEntry.getKey(), new ArrayList<CountModel>());
				}
				BigDecimal storageNum = BigDecimal.ZERO;
				if(storageEntry.getValue() != null){
					storageNum = storageEntry.getValue().getCount();
				}
				BigDecimal safeStock = itemWithSubExtendsVO.getItemStoreProp().getSafeStock();
				if(safeStock == null){
					safeStock = BigDecimal.ZERO;
				}
				
				storageNum = storageNum.subtract(safeStock);
				
				if(storageNum.compareTo(BigDecimal.ZERO) == -1 && resultCountModelsMap.get(storageEntry.getKey()).size() == 0){
					//库存小于安全库存且无后续订单
					CountModel safeStockModel = new CountModel();
					safeStockModel.setCount(storageNum.abs().setScale(scale, BigDecimal.ROUND_UP));
					safeStockModel.setItemCode(itemWithSubExtendsVO.getItemCode());
					safeStockModel.setOrderDate(new Date());
					
					safeStockModel.setRemark(itemWithSubExtendsVO.getItemCode()+"安全库存备货("+storageNum.abs().setScale(scale, BigDecimal.ROUND_UP).doubleValue()+")");
					
					safeStockModel.setIndexes(storageEntry.getKey());
					if(allmodels.get(storageEntry.getKey()) == null) {
						allmodels.put(storageEntry.getKey(), new ArrayList<CountModel>());
					}
					//allmodels.get(storageEntry.getKey()).add(safeStockModel);
					allmodels.get(storageEntry.getKey()).addAll(computeLotSize(itemWithSubExtendsVO, storageEntry.getKey(), safeStockModel));
					storageNum = BigDecimal.ZERO;
				}else{
					//库存大于安全库存 或者 库存小于安全库存且存在后续订单
					Iterator<CountModel> it = resultCountModelsMap.get(storageEntry.getKey()).iterator();
					while(it.hasNext()){
						CountModel x = it.next();
						if(x.getType()!=null&&x.getType() == 1){
							storageNum = storageNum.subtract(x.getCount());
						}else if(x.getType()!=null&&x.getType() == 2){
							storageNum = storageNum.add(x.getCount());
						}else{
							storageNum = storageNum.add(x.getCount());
						}
						if(storageNum.compareTo(BigDecimal.ZERO) == -1){
							CountModel countodel = new CountModel();
							countodel.setCount(storageNum.abs());
							countodel.setItemCode(itemWithSubExtendsVO.getItemCode());
							countodel.setOrderDate(x.getOrderDate());
							if(storageNum.abs().compareTo(x.getCount()) == 1) {
								countodel.setRemark(itemWithSubExtendsVO.getItemCode()+"安全库存备货("+storageNum.abs().subtract(x.getCount()).setScale(scale, BigDecimal.ROUND_UP).doubleValue()+")");
							}else {
								countodel.setRemark(x.getRemark()+"("+x.getCount().setScale(scale, BigDecimal.ROUND_UP).doubleValue()+")");
							}
							
							countodel.setIndexes(x.getIndexes());
							if(allmodels.get(storageEntry.getKey()) == null) {
								allmodels.put(storageEntry.getKey(), new ArrayList<CountModel>());
							}
							//allmodels.get(storageEntry.getKey()).add(countodel);
							allmodels.get(storageEntry.getKey()).addAll(computeLotSize(itemWithSubExtendsVO, storageEntry.getKey(), countodel));
							storageNum = BigDecimal.ZERO;
						}
					}
				}
			}
			
			/////////////////////
			for(Map.Entry<String, List<CountModel>> entry : allmodels.entrySet()) {
				Collections.sort(entry.getValue());
			}
			
			context.getResultCount().put(itemWithSubExtendsVO.getItemCode(), resultCountModelsMap);
			context.getAllmodels().put(itemWithSubExtendsVO.getItemCode(), allmodels);
		}
	}
	
	private List<CountModel> computeLotSize(ItemWithSubExtendsVO item, String key, CountModel countModel){
		List<CountModel> result = new ArrayList<>();
		if(context.getLotCount().get(item.getItemCode()) == null){
			context.getLotCount().put(item.getItemCode(), new HashMap<String, CountModel>());
		}
		CountModel lotSizeCount = context.getLotCount().get(item.getItemCode()).get(key);
		if(lotSizeCount != null){
			countModel.setCount(countModel.getCount().add(lotSizeCount.getCount()));
		}
		if(BigDecimal.ZERO.compareTo(countModel.getCount())<0){
			BigDecimal fixedLotSize = item.getItemPlanProp().getFixedLotSize();
			BigDecimal incrementLotSize = item.getItemPlanProp().getIncrementLotSize();
			BigDecimal minPlanQuantity = item.getItemPlanProp().getMinPlanQuantity();
			// 固定批量存在,需求大于固定批量,则按照固定批量分隔订单
			if (fixedLotSize != null && BigDecimal.ZERO.compareTo(fixedLotSize) != 0) {
				int planCount = countModel.getCount().divide(fixedLotSize, 0, BigDecimal.ROUND_UP).intValue();
				for(int i=0; i<planCount; i++){
					CountModel subCountModel = new CountModel();
					BeanReflectionUtils.copyProperties(subCountModel, countModel);
					subCountModel.setCount(fixedLotSize);
					result.add(subCountModel);
				}
				CountModel currentCountModel = new CountModel();
				BeanReflectionUtils.copyProperties(currentCountModel, countModel);
				currentCountModel.setCount(currentCountModel.getCount().subtract(fixedLotSize.multiply(new BigDecimal(planCount))));
				context.getLotCount().get(item.getItemCode()).put(key, currentCountModel);
			}else if((minPlanQuantity!=null && BigDecimal.ZERO.compareTo(minPlanQuantity)!=0)
					&& (incrementLotSize!=null && BigDecimal.ZERO.compareTo(incrementLotSize)!=0)){
				// 固定批量不存在，按照批量和增量计算
				CountModel subCountModel = new CountModel();
				BeanReflectionUtils.copyProperties(subCountModel, countModel);
				BigDecimal quantity = BigDecimal.ZERO;
				if(minPlanQuantity.compareTo(countModel.getCount())<0){
					quantity = minPlanQuantity.add(countModel.getCount().subtract(minPlanQuantity).divide(incrementLotSize, 0, BigDecimal.ROUND_UP).multiply(incrementLotSize));
				}else{
					quantity = minPlanQuantity;
				}
				subCountModel.setCount(quantity);
				result.add(subCountModel);
				CountModel currentCountModel = new CountModel();
				BeanReflectionUtils.copyProperties(currentCountModel, countModel);
				currentCountModel.setCount(countModel.getCount().subtract(quantity));
				context.getLotCount().get(item.getItemCode()).put(key, currentCountModel);
			}else{
				// 如果批次不存在，则为净需求
				result.add(countModel);
			}
		}else{
			lotSizeCount.setCount(countModel.getCount());
		}
		
		return result;
	}
}
